<?php
class Utils {
	const MD5_HASH = 'md5';
	public static function transliterate($text){
		$text = preg_replace("/[ạáàảãâậấầẩẫăặắằẳẫäæå]/u","a",$text);
		$text = preg_replace("/[ẠÁÀẢÃÂẬẤẦẨẪĂẮẰẲẴẶÄÆÅ]/u","A",$text);
		$text = preg_replace("/[þ]/u","b",$text);
		$text = preg_replace("/[Þ]/u","B",$text);
		$text = preg_replace("/[ç]/u","c",$text);
		$text = preg_replace("/[Ç]/u","C",$text);
		$text = preg_replace("/[đð]/u","d",$text);
		$text = preg_replace("/[Đ]/u","D",$text);
		$text = preg_replace("/[ẹéèẻẽêếềểễệë]/u","e",$text);
		$text = preg_replace("/[ẸÉÈẺẼÊẾỀỂỄỆË]/u","E",$text);
		$text = preg_replace("/[ịíìỉĩîï]/u","i",$text);
		$text = preg_replace("/[ỊÍÌỈĨÎÏ]/u","I",$text);
		$text = preg_replace("/[ñ]/u","n",$text);
		$text = preg_replace("/[Ñ]/u","N",$text);
		$text = preg_replace("/[óòỏõọôốồổỗộơớờởỡợöøº]/u","o",$text);
		$text = preg_replace("/[ÓÒỎÕỌÔỐỒỔỖỘƠỚỜỞỠỢÖØ]/u","O",$text);
		$text = preg_replace("/[úùủũụưứừửữựûü]/u","u",$text);
		$text = preg_replace("/[ÚÙỦŨỤƯỨỪỬỮỰÛÜ]/u","U",$text);
		$text = preg_replace("/[ŕ]/u","r",$text);
		$text = preg_replace("/[Ŕ]/u","R",$text);
		$text = preg_replace("/[š]/u","s",$text);
		$text = preg_replace("/[Š]/u","S",$text);
		$text = preg_replace("/[ýỳỷỹỵŷÿ]/u","y",$text);
		$text = preg_replace("/[ÝỲỶỸỴŶŸ]/u","Y",$text);
		$text = preg_replace("/[ž]/u","z",$text);
		$text = preg_replace("/[Ž]/u","Z",$text);
		return preg_replace('/[^a-z0-9\s]/i', '', iconv("UTF-8", "US-ASCII//TRANSLIT", $text));
	}
	public static function uri_encode($text, $length=0){
		$text = preg_replace('/(-{2,})|(\.{2,})+/', '-', strtolower(trim(preg_replace('/[^\w.]|[|_]+/', '-', self::transliterate($text)), '-')));
		if(is_int($length) && $length > 0 && mb_strlen($text, "UTF-8") > $length) 
		{
			$text = mb_substr($text, 0, $length, "UTF-8");
		}
		return urlencode($text);
		//Read more: http://msdn.microsoft.com/en-us/library/az24scfc.aspx
		//return $text = strtolower(trim(preg_replace('/[\W|_]+/','-',self::latin1_to_ascii($texting)),'-'));
	}
	public static function nrcdecimal_to_utf8($text) {
		return html_entity_decode($text,ENT_NOQUOTES,'UTF-8');
	}
	public static function truncate($text, $length, $etc="..."){
		return preg_replace('/\s+?(\S+)?$/', $etc, substr($text, 0, (int)$length));	
	}
	public static function getCurrentUrl() {
		$url = "http://";
		if (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on") {
			$url = "https://";
		}
		if ($_SERVER["SERVER_PORT"] != "80") {
			$url .= $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
		} else {
			$url .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
		}
		return $url;
	}
	public static function getIp() {
		if (!empty($_SERVER['HTTP_CLIENT_IP']))   //check ip from share internet
		{
			$ip=$_SERVER['HTTP_CLIENT_IP'];
		}
		elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))   //to check ip is pass from proxy
		{
			$ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
		}
		else
		{
			$ip=$_SERVER['REMOTE_ADDR'];
		}
		return $ip;
	}
	
	//Geocoding is the process of finding associated geographic coordinates (often expressed as latitude and longitude) from other geographic data, such as street addresses, or ZIP codes (postal codes).
	public static function geocoding($address){
		//check if curl is installed?
		if(!in_array('curl', get_loaded_extensions())) {
			throw new Exception('cURL is NOT installed on your server!');
		}
		$url = "http://maps.googleapis.com/maps/api/geocode/json?address=".str_replace (" ", "+", urlencode($address));
		//query google
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		$response = json_decode(curl_exec($ch), true);
		// If Status Code is ZERO_RESULTS, OVER_QUERY_LIMIT, REQUEST_DENIED or INVALID_REQUEST
		if ($response['status'] != 'OK') {
			return false;
		}
		$results = $response['results'];
		return array(
			'formatted_address' => $results[0]['formatted_address'],
			'latitude' => $results[0]['geometry']['location']['lat'],
			'longitude' => $results[0]['geometry']['location']['lng'],
			'location_type' => $results[0]['geometry']['location_type']
		); 
	}
		
	/**
     * Generates random strings
     *
     * @param Integer $length The limited value to return (default: 5)
     *
	 * @return String The generated, base64 encoded token.
     */
	public static function getRandomString($length = 5){
		$chars =  'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
				 .'abcdefghijklmnopqrstuvwxyz'
				 .'0123456789'
				 //.'`-=~!@#$%^&*()_+,./<>?;:[]{}\|'
				 ;
		$length = intval($length);
		//Method 1
		return substr(str_shuffle(str_repeat($chars,$length)),0,$length);
		//Method 2
		/*$str = '';
		$max = strlen($chars) - 1;
		for ($i=0; $i < $length; $i++){
			$str .= substr($chars,mt_rand(0, $max),1);
		}
		return $str;*/
	}
	
	/**
     * Generates CSRF token.
     *
     * @param String $namespace The session token name where the token will be retrieved. (It should be the same name with the hidden field name)
     * @param Integer $timeout Forces the token expire after $timeout seconds. (null = never)
	 * 
	 * @return String The generated, base64 encoded token.
     */
	public static function generateToken($namespace, $timeout = 3600){
		if(!isset($_SESSION)) session_start();
		$token = md5(uniqid(rand(), true));
		$_SESSION['csrf'][$namespace] = array(
			'token' => $token,
			'time' => time(),
			'timeout' => $timeout
		);	
		return $token;
	}
	
	/**
     * Checks if input CSRF token is valid. Make sure you generated a token in the form before checking it.
     *
     * @param String $namespace The session token name where we retrieve the token.
     * @param String $token The input CSRF token.
	 * @param Boolean $ott (One-Time Token) TRUE to make the token reusable and not one-time. (Useful for ajax-heavy requests).
     * @param Boolean $exception TRUE to throw exception on check fail, FALSE or default to return false.
	 *
     * @return Boolean Returns FALSE if a CSRF attack is detected, TRUE otherwise.
     */
	public static function verifyToken($namespace, $token, $ott = true, $exception = false){
		if (!isset($_SESSION['csrf'][$namespace]) || !isset($_SESSION['csrf'][$namespace]['token']) || !isset($_SESSION['csrf'][$namespace]['time'])  || !isset($_SESSION['csrf'][$namespace]['timeout'])){
			if($exception)
				throw new Exception('Missing session token.');
			else
				return false;
		}
		
		// Get valid token from session
		$hash = $_SESSION['csrf'][$namespace];

		//Free up session token for one-time token usage.
		if($ott){
			$_SESSION['csrf'][$namespace] = null;
		}
		
		//Check if session token matches form input token
		if($hash['token'] != $token){
			if($exception)
				throw new Exception('Invalid token.');
			else
				return false;
		}
		
		//check if token is expired
		if($hash['time'] !== null && $hash['time']+$hash['timeout'] < time()){
			if($exception)
				throw new Exception('Token has expired.');
			else
				return false;
		}
		return true;
	}
		
	/**
     * Creates a new password hash using a strong one-way hashing algorithm
     *
     * @param String $password The user's password.
     * @param String $method (optional, default md5) A password algorithm is used when hashing the password.
	 *
     * @return the hashed password, or FALSE on failure
     */
	public static function hashPassword($password, $method = 'md5'){
		switch($method){
			case 'md5': //HASH PASWORD BY USING MD5()
			{
				return md5($password);	
			}
			case 'phpass': //HASH PASSWORD BY USING BLOWFISH via PHPASS 
			{
				require_once('phpass/PasswordHash.php');
				$hasher = new PasswordHash(8, false);
				$hash = $hasher->HashPassword($password);
				if (strlen($hash)<20){
					throw new Exception('Error occurs, please try again or contact your administrator!');
				}
				return $hash;
			}
			default:
			{
				return md5($password);
			}
		}				
	}
		
	/**
     * Verifies that a password matches a hash. Make sure given hash and given password are generated by the same algorithm.
     *
     * @param String $password The user's password.
     * @param String $hash A hash created by hashPassword function.
	 * @param String $method (optional, default md5). The hasing algorithm is used when verify the password.
	 *
     * @return the hashed password, or FALSE on failure
     */
	public static function verifyPassword($password, $hash, $method = 'md5'){
		switch($method){
			case 'md5': //VERIFY PASSWORD BY USING MD5()
			{
				return (md5($password) === $hash);
			}
			case 'phpass': //VERIFY PASSWORD BY USING PHPASS 
			{
				require_once('phpass/PasswordHash.php');
				$hasher = new PasswordHash(8, false);
				return $hasher->CheckPassword($password, $hash);
			}
			default:
			{
				return (md5($password) === $hash);
			}
		}
	}
}